#pragma once

#ifdef _WIN32
// Windows API头文件
#include <windows.h>
#include <dbghelp.h>
#include <tlhelp32.h>
#include <iostream>

// Qt库头文件
#include <QFile>
#include <QDir>
#include <QDateTime>
#include <QSysInfo>
#include <QStandardPaths>
#include <QTextStream>

#include "logger.h"

#ifdef _MSC_VER
#pragma message("Compiling with MSVC")
#pragma comment(lib, "dbghelp.lib")
#endif

// 在Windows平台上定义POSIX信号常量，用于与平台无关的信号处理
#ifndef SIGSEGV
#define SIGSEGV 11
#endif
#ifndef SIGFPE
#define SIGFPE 8
#endif
#ifndef SIGILL
#define SIGILL 4
#endif
#ifndef SIGABRT
#define SIGABRT 6
#endif
#ifndef SIG_DFL
#define SIG_DFL ((void (*)(int))0)
#endif

// Windows平台模拟signal和raise函数
inline void signal(int signum, void (*handler)(int)) {
    // 在Windows上，这只是一个桩函数，实际不做任何事情
    // 因为Windows有自己的异常处理机制
}

inline void raise(int signum) {
    // 在Windows上，这只是一个桩函数，实际不做任何事情
}

class CCrashStack
{
private:
	PEXCEPTION_POINTERS m_pException;

	QString GetModuleByRetAddr(PBYTE Ret_Addr, PBYTE& Module_Addr)
	{
		MODULEENTRY32   M = { sizeof(M) };
		HANDLE  hSnapshot;
		wchar_t Module_Name[MAX_PATH] = { 0 };
		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
		if ((hSnapshot != INVALID_HANDLE_VALUE) &&
			Module32First(hSnapshot, &M))
		{
			do
			{
				if (DWORD(Ret_Addr - M.modbaseAddr) < M.modbaseSize)
				{
					wchar_t wExePath[MAX_PATH] = { 0 };
					//MultiByteToWideChar(CP_ACP, 0, M.szExePath, -1, wExePath, MAX_PATH);
					lstrcpynW(Module_Name, wExePath, MAX_PATH);
					Module_Addr = M.modbaseAddr;
					break;
				}
			} while (Module32Next(hSnapshot, &M));
		}
		CloseHandle(hSnapshot);
		QString sRet = QString::fromWCharArray(Module_Name);
		return sRet;
	}

	QString GetCallStack(PEXCEPTION_POINTERS pException)
	{
		PBYTE   Module_Addr_1;
		char bufer[256] = { 0 };
		QString sRet;
		typedef struct STACK
		{
			STACK* Ebp;
			PBYTE   Ret_Addr;
			DWORD   Param[0];
		} STACK, * PSTACK;
		STACK   Stack = { 0, 0 };
		PSTACK  Ebp;
		if (pException)     //fake frame for exception address
		{
#ifdef _M_IX86
			Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;
#elif _M_X64
			Stack.Ebp = (PSTACK)pException->ContextRecord->Rbp;
#endif
			Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;
			Ebp = &Stack;
		}
		else
		{
			Ebp = (PSTACK)&pException - 1;  //frame addr of Get_Call_Stack()
			// Skip frame of Get_Call_Stack().
			if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))
				Ebp = Ebp->Ebp;     //caller ebp
		}
		// Break trace on wrong stack frame.
		for (; !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));
			Ebp = Ebp->Ebp)
		{
			// If module with Ebp->Ret_Addr found.
			memset(bufer, 0, sizeof(0));
			sprintf(bufer, "\n%08X  ", (unsigned int)Ebp->Ret_Addr);
			sRet.append(bufer);
			QString moduleName = this->GetModuleByRetAddr(Ebp->Ret_Addr, Module_Addr_1);
			if (moduleName.length() > 0)
			{
				sRet.append(moduleName);
			}
		}
		return sRet;
	} //Get_Call_Stack

	QString GetVersionStr()
	{
		OSVERSIONINFOEX V = { sizeof(OSVERSIONINFOEX) };  //EX for NT 5.0 and later
		if (!GetVersionEx((POSVERSIONINFO)&V))
		{
			ZeroMemory(&V, sizeof(V));
			V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
			GetVersionEx((POSVERSIONINFO)&V);
		}
		if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)
			V.dwBuildNumber = LOWORD(V.dwBuildNumber);  //for 9x HIWORD(dwBuildNumber) = 0x04xx
		QString sRet;
		sRet.append(QString("Windows:  %1.%2.%3, SP %4.%5, Product Type %6\n")
			.arg(V.dwMajorVersion).arg(V.dwMinorVersion).arg(V.dwBuildNumber)
			.arg(V.wServicePackMajor).arg(V.wServicePackMinor).arg(V.wProductType));
		return sRet;
	}

public:
	CCrashStack(PEXCEPTION_POINTERS pException)
	{
		m_pException = pException;
	}

	QString GetExceptionInfo()
	{
		WCHAR       Module_Name[MAX_PATH];
		PBYTE       Module_Addr;
		QString sRet;
		QString crashLog;
		char buffer[512] = { 0 };
		QString sTmp = GetVersionStr();
		crashLog.append(sTmp);
		crashLog.append("Process:  ");
		GetModuleFileNameW(NULL, Module_Name, MAX_PATH);
		crashLog.append(QString::fromWCharArray(Module_Name));
		crashLog.append("\n");
		// If exception occurred.
		if (m_pException)
		{
			EXCEPTION_RECORD& E = *m_pException->ExceptionRecord;
			CONTEXT& C = *m_pException->ContextRecord;

			// 打印异常代码

			switch (m_pException->ExceptionRecord->ExceptionCode) {
			case EXCEPTION_ACCESS_VIOLATION:
				crashLog += QString("Access violation at address 0x%1 (code 0x%2)\n")
					.arg((quintptr)m_pException->ExceptionRecord->ExceptionAddress, 0, 16)
					.arg(m_pException->ExceptionRecord->ExceptionCode, 0, 16);
				break;

			case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
				crashLog += "Array bounds exceeded\n";
				break;

			case EXCEPTION_FLT_DENORMAL_OPERAND:
				crashLog += "Denormal operand\n";
				break;

			case EXCEPTION_FLT_DIVIDE_BY_ZERO:
				crashLog += "Floating point divide by zero\n";
				break;

			case EXCEPTION_FLT_INEXACT_RESULT:
				crashLog += "Inexact floating point result\n";
				break;

			case EXCEPTION_FLT_INVALID_OPERATION:
				crashLog += "Invalid floating point operation\n";
				break;

			case EXCEPTION_FLT_OVERFLOW:
				crashLog += "Floating point overflow\n";
				break;

			case EXCEPTION_FLT_STACK_CHECK:
				crashLog += "Floating point stack check\n";
				break;

			case EXCEPTION_FLT_UNDERFLOW:
				crashLog += "Floating point underflow\n";
				break;

			case EXCEPTION_INT_DIVIDE_BY_ZERO:
				crashLog += "Integer divide by zero\n";
				break;

			case EXCEPTION_INT_OVERFLOW:
				crashLog += "Integer overflow\n";
				break;
			default:
				crashLog += QString("Unknown exception at address 0x%1 (code 0x%2)")
					.arg((quintptr)m_pException->ExceptionRecord->ExceptionAddress, 0, 16)
					.arg(m_pException->ExceptionRecord->ExceptionCode, 0, 16);
				break;
			}

			// 获取堆栈跟踪
			HANDLE process = GetCurrentProcess();
			HANDLE thread = GetCurrentThread();
			CONTEXT context = *m_pException->ContextRecord;


			STACKFRAME64 stackFrame;
			memset(&stackFrame, 0, sizeof(STACKFRAME64));

#ifdef _M_IX86
			DWORD machineType = IMAGE_FILE_MACHINE_I386;
			stackFrame.AddrPC.Offset = context.Eip;
			stackFrame.AddrPC.Mode = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.Ebp;
			stackFrame.AddrFrame.Mode = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.Esp;
			stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
			DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
			stackFrame.AddrPC.Offset = context.Rip;
			stackFrame.AddrPC.Mode = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.Rsp;
			stackFrame.AddrFrame.Mode = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.Rsp;
			stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
			DWORD machineType = IMAGE_FILE_MACHINE_IA64;
			stackFrame.AddrPC.Offset = context.StIIP;
			stackFrame.AddrPC.Mode = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.IntSp;
			stackFrame.AddrFrame.Mode = AddrModeFlat;
			stackFrame.AddrBStore.Offset = context.RsBSP;
			stackFrame.AddrBStore.Mode = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.IntSp;
			stackFrame.AddrStack.Mode = AddrModeFlat;
#endif
#ifdef _MSC_VER
#pragma message("Compiling with MSVC")
#if _MSC_VER >= 1920
#pragma message("MSVC version is 2019 or later")
			SymInitialize(process, NULL, TRUE);

			while (StackWalk64(machineType, process, thread, &stackFrame, &context, NULL, SymFunctionTableAccess64, SymGetModulebase64, NULL))
			{
				DWORD64 address = stackFrame.AddrPC.Offset;
				if (address == 0)
				{
					break;
				}

				// 获取符号信息
				DWORD64 displacement = 0;
				char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
				PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
				symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
				symbol->MaxNameLen = MAX_SYM_NAME;

				// 获取模块信息
				IMAGEHLP_MODULE64 moduleInfo;
				moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);

				char addressStr[32] = { 0 };
				sprintf(addressStr, "0x%016llX", address);
				crashLog += QString("  %1").arg(addressStr);

				if (SymFromAddr(process, address, &displacement, symbol))
				{
					crashLog += QString(" %1").arg(symbol->Name);
				}

				if (SymGetModuleInfo64(process, address, &moduleInfo))
				{
					crashLog += QString(" in %1").arg(moduleInfo.ModuleName);
				}

				crashLog += "\n";
			}
#endif
#endif
		}

		// 使用Logger记录崩溃信息
		Logger::instance()->critical("程序崩溃，正在生成崩溃报告...");
		
		// 使用新的writeCrashLog方法保存崩溃日志
		Logger::writeCrashLog(crashLog);

		return crashLog;
	}

	QString GetCallStack() {
		return GetCallStack(m_pException);
	}
};

// Windows平台的信号处理函数（模拟POSIX信号API）
void signalHandler(int signum) {
	QString msg = QString("收到信号: %1").arg(signum);
	switch (signum) {
	case SIGSEGV:
		msg += " (段错误)";
		break;
	case SIGFPE:
		msg += " (浮点错误)";
		break;
	case SIGILL:
		msg += " (非法指令)";
		break;
	case SIGABRT:
		msg += " (异常终止)";
		break;
	default:
		msg += " (未知信号)";
		break;
	}

	Logger::instance()->critical(msg);

	// 在Windows上，这些函数实际不会被调用，只是为了保持代码结构一致
	signal(signum, SIG_DFL);
	raise(signum);
}

#else // 非Windows平台

// 在Unix/Linux平台实现信号处理
#include <signal.h>
#include <QString>
#include "logger.h"

void signalHandler(int signum) {
	QString msg = QString("收到信号: %1").arg(signum);
	switch (signum) {
	case SIGSEGV:
		msg += " (段错误)";
		break;
	case SIGFPE:
		msg += " (浮点错误)";
		break;
	case SIGILL:
		msg += " (非法指令)";
		break;
	case SIGABRT:
		msg += " (异常终止)";
		break;
	default:
		msg += " (未知信号)";
		break;
	}

	Logger::instance()->critical(msg);

	// 恢复默认处理并重新引发信号
	signal(signum, SIG_DFL);
	raise(signum);
}

#endif // _WIN32 